package JsonMarshal

import (
	"reflect"
	"bytes"
)

type encoderFunc func(e *encodeState, v reflect.Value)
type encodeState struct {
	bytes.Buffer
	// Keep track of what pointers we've seen in the current recursive call
	// path, to avoid cycles that could lead to a stack overflow. Only do
	// the relatively expensive map operations if ptrLevel is larger than
	// startDetectingCyclesAfter, so that we skip the work if we're within a
	// reasonable amount of nested pointers deep.
	ptrLevel uint
	ptrSeen  map[interface{}]struct{}
}

func JsonMarshal(v interface{}) ([]byte, error) {
	e := &encodeState{}
	
	if err := e.marshal(v); err != nil {
		return nil, err
	}
	
	ret := append([]byte(nil), e.Bytes()...)
	return ret, nil
}

func (e *encodeState) marshal(v interface{}) (err error) {
	defer func() {
		if r := recover(); r != nil {
			if je, ok := r.(jsonError); ok {
				err = je.error
			} else {
				panic(r)
			}
		}
	}()

	v_val := reflect.ValueOf(v)
	valueEncoder(v_val)(e, v_val)
	return nil
}

func valueEncoder(v reflect.Value) encoderFunc {
	if !v.IsValid() {
		return invalidValueEncoder
	}
	return typeEncoder(v.Type())
}

func typeEncoder(t reflect.Type) encoderFunc {
	switch t.Kind() {
	case reflect.Struct:
		return newStructEncoder(t)
	case reflect.Map:
		return newMapEncoder(t)
	case reflect.Slice, reflect.Array:
		return newArrayEncoder(t)
	case reflect.Ptr:
		return newPtrEncoder(t)
	case reflect.Interface:
		return interfaceEncoder
	case reflect.String, reflect.Bool, 
		 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
		 reflect.Float32, reflect.Float64:
		return basicEncoder
	default:
		return unsupportedTypeEncoder
	}
}